import { Cartesian3, Cartesian4, CullingVolume, Matrix4 } from "cesium";
// import CullingVolume from "./CullingVolume";
export default class PerspectiveFrustum {
    private _near: number;    // 近裁剪面距离
    private _far: number;     // 远裁剪面距离
    private _fovy: number;     // 视场角度，通常以度为单位
    private _aspectRatio: number; // 宽高比
    private _projectionMatrix: Matrix4;
    private _cullingVolume: CullingVolume;
    constructor(near: number = 0.1, far: number = 10000000.0, fov: number = Math.PI / 3, aspectRatio: number = 1.0) {
        this._near = near;
        this._far = far;
        this._fovy = fov;
        this._aspectRatio = aspectRatio;
        this._projectionMatrix = new Matrix4();
    }


    public get ProjectionMatrix() {
        var height = 2 * this._near * Math.tan(this._fovy / 2);
        var width = height * this._aspectRatio;
        var left = -width / 2;
        var right = width / 2;
        var bottom = -height / 2;
        var top = height / 2;
        // 使用 Matrix4.computePerspectiveOffCenter 生成对称透视投影矩阵
        Matrix4.computePerspectiveOffCenter(left, right, bottom, top, this._near, this._far, this._projectionMatrix);
        return this._projectionMatrix;
    }


    public get fovy(): number {
        return this._fovy
    }


    public get aspectRatio(): number {
        return this._aspectRatio;
    }
    
    public get near() : number {
        return this._near;
    }
    

    public computeCullingVolume(position: Cartesian3, direction: Cartesian3, up: Cartesian3) {
        var height = 2 * this._near * Math.tan(this._fovy / 2);
        var width = height * this._aspectRatio;
        var left = -width / 2;
        var right = width / 2;
        var bottom = -height / 2;
        var top = height / 2;
        const cameraRight = new Cartesian3();
        const nearCenter = new Cartesian3();
        //相机右方向
        Cartesian3.cross(direction, up, cameraRight);
        //视锥体近中心
        Cartesian3.multiplyByScalar(direction, this._near, nearCenter);
        Cartesian3.add(position, nearCenter, nearCenter);
        //视锥体远中心
        const farCenter = new Cartesian3();
        Cartesian3.multiplyByScalar(direction, this._far, farCenter);
        Cartesian3.add(position, farCenter, farCenter);

        const normal = new Cartesian3();

        //Left plane computation
        Cartesian3.multiplyByScalar(cameraRight, left, normal);
        Cartesian3.add(nearCenter, normal, normal);
        Cartesian3.subtract(normal, position, normal);
        Cartesian3.normalize(normal, normal);
        Cartesian3.cross(normal, up, normal);
        Cartesian3.normalize(normal, normal);
        let planes: Cartesian4[] = [];
        let plane = new Cartesian4(normal.x, normal.y, normal.z, Cartesian3.dot(position, normal));
        planes.push(plane);
        //Right plane computation
        Cartesian3.multiplyByScalar(cameraRight, right, normal);
        Cartesian3.add(nearCenter, normal, normal);
        Cartesian3.subtract(normal, position, normal);
        Cartesian3.cross(up, normal, normal);
        Cartesian3.normalize(normal, normal);
        plane = new Cartesian4(normal.x, normal.y, normal.z, Cartesian3.dot(position, normal));
        planes.push(plane);
        //Bottom plane computation
        Cartesian3.multiplyByScalar(up, bottom, normal);
        Cartesian3.add(nearCenter, normal, normal);
        Cartesian3.subtract(normal, position, normal);
        Cartesian3.cross(cameraRight, normal, normal);
        Cartesian3.normalize(normal, normal);
        plane = new Cartesian4(normal.x, normal.y, normal.z, Cartesian3.dot(position, normal));
        planes.push(plane);
        //Top plane computation
        Cartesian3.multiplyByScalar(up, top, normal);
        Cartesian3.add(nearCenter, normal, normal);
        Cartesian3.subtract(normal, position, normal);
        Cartesian3.cross(normal, cameraRight, normal);
        Cartesian3.normalize(normal, normal);
        plane = new Cartesian4(normal.x, normal.y, normal.z, Cartesian3.dot(position, normal));
        planes.push(plane);
        //Near plane computation
        plane = new Cartesian4(direction.x, direction.y, direction.z, -Cartesian3.dot(nearCenter, direction));
        planes.push(plane);
        //Far plane computation
        plane = new Cartesian4(direction.x, direction.y, direction.z, -Cartesian3.dot(farCenter, direction));
        planes.push(plane);
        let cullingVolume = new CullingVolume(planes);
        return cullingVolume;
    }


}
